package com.luo.d3s.ext.event.jdbc.publish;

import com.luo.d3s.core.domain.event.DomainEvent;
import com.luo.d3s.core.domain.event.DomainEventRepository;
import net.javacrumbs.shedlock.core.LockAssert;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 领域事件 - 补偿发布器
 *
 * @author luohq
 * @date 2023-02-25 09:37
 */
@Component
public class DomainEventCompensatePublisher {

    private static final Logger log = LoggerFactory.getLogger(DomainEventCompensatePublisher.class);

    @Resource
    private DomainEventRepository domainEventRepository;
    @Resource
    private DomainEventPublisherDispatcher domainEventPublisherDispatcher;

    @Value("${d3s.events.publish.compensate-delay-seconds:5}")
    private Long compensateDelayMills;

    /**
     * 定时调度 - 查询并发送领域事件
     */
    @Scheduled(fixedDelayString = "${d3s.events.publish.compensate-interval-seconds:3}", timeUnit = TimeUnit.SECONDS)
    @SchedulerLock(name = "dddEventsSchedulerTask")
    public void publishCompensatePeriodically() {
        // To assert that the lock is held (prevents misconfiguration errors)
        LockAssert.assertLocked();
        //定时查询待发送的领域事件
        List<DomainEvent> domainEvents = this.domainEventRepository.toPublish(LocalDateTime.now().minusSeconds(this.compensateDelayMills));
        log.debug("To publish event count: {}", Optional.ofNullable(domainEvents).map(List::size).orElse(0));
        //待发送事件列表为空则直接结束
        if (CollectionUtils.isEmpty(domainEvents)) {
            return;
        }
        domainEvents.forEach(domainEvent -> {
            //根据类型发送领域事件
            this.domainEventPublisherDispatcher.publishByType(domainEvent);
            //更新事件为已发送状态
            this.domainEventRepository.published(domainEvent);
        });

    }
}
